package com.mm.cloud.sys.auth.core.provider;

import com.mm.cloud.common.core.enums.PermissionPlatformTypeEnum;
import com.mm.cloud.common.core.exception.BaseException;
import com.mm.cloud.common.redis.constant.RedisKeySystemConstants;
import com.mm.cloud.common.redis.service.IRedisService;
import com.mm.cloud.common.redis.util.RedisKeyStringUtils;
import com.mm.cloud.common.security.helper.LoginUserHelper;
import com.mm.cloud.common.security.loginuser.LoginToken;
import com.mm.cloud.common.security.loginuser.LoginUser;
import com.mm.cloud.sys.auth.core.provider.base.AuthenticationProvider;
import com.mm.cloud.sys.auth.core.token.base.AuthenticateToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
 * 身份验证提供者管理器
 *
 * @author mr
 * @since 2021-07-10
 */
@Slf4j
@Primary
@Component
public class ProviderManager implements AuthenticationProvider {

    @Autowired
    private IRedisService<String, Object> redisService;

    private final List<AuthenticationProvider> providers;

    public ProviderManager(AuthenticationProvider... providers) {
        this.providers = Arrays.asList(providers);
    }

    @Override
    public LoginToken authenticate(AuthenticateToken authenticateToken) {
        Class<? extends AuthenticateToken> toTest = authenticateToken.getClass();
        Iterator<AuthenticationProvider> iterator = this.providers.iterator();
        Object obj = null;
        while (iterator.hasNext()) {
            AuthenticationProvider provider = iterator.next();
            if (provider.supports(toTest)) {
                obj = provider.authenticate(authenticateToken);
                break;
            }
        }
        if (ObjectUtils.isEmpty(obj)) {
            throw new BaseException("登录失败，请联系管理员");
        }
        LoginUser loginUser = (LoginUser) obj;
        redisService.set(RedisKeyStringUtils.appendRedisKey(RedisKeySystemConstants.REDIS_TOKEN, loginUser.getToken()), loginUser, RedisKeySystemConstants.RedisCacheTimeEnum.TOKEN.getTime(), RedisKeySystemConstants.RedisCacheTimeEnum.TOKEN.getUnit());
        //offline(loginUser.getUsername(), token);
        return new LoginToken(loginUser.getToken(), RedisKeySystemConstants.RedisCacheTimeEnum.TOKEN.getTime());
    }

    /**
     * 下线已登录的用户
     *
     * @param username 用户名
     * @param token token
     */
    public void offline(String username, String token) {
        String key = RedisKeyStringUtils.appendRedisKey(RedisKeySystemConstants.REDIS_LOGIN, username);
        Object o = redisService.get(key);
        if (!ObjectUtils.isEmpty(o)) {
            redisService.delete(RedisKeyStringUtils.appendRedisKey(RedisKeySystemConstants.REDIS_TOKEN, (String) o));
        }
        redisService.set(key, token, RedisKeySystemConstants.RedisCacheTimeEnum.TOKEN.getTime(), RedisKeySystemConstants.RedisCacheTimeEnum.TOKEN.getUnit());
    }

    /**
     * 注销
     */
    public void logout() {
        final String token = LoginUserHelper.getToken();
        if (StringUtils.isNotEmpty(token)) {
            final LoginUser loginUser = LoginUserHelper.getLoginUser();
            if (!ObjectUtils.isEmpty(loginUser)) {
                // 删除缓存菜单
                for (PermissionPlatformTypeEnum tEnum : PermissionPlatformTypeEnum.values()) {
                    //删除缓存菜单 平台类型 1-平台管理 2-商城管理
                    final String key = RedisKeyStringUtils.appendRedisKey(RedisKeySystemConstants.REDIS_INIT_PERMISSION, token, tEnum.getType());
                    redisService.delete(key);
                }
                //删除缓存用户
//                final String key2 = RedisKeyStringUtils.appendRedisKey(RedisKeySystemConstants.REDIS_LOGIN, loginUser.getUsername());
//                redisService.delete(key2);
            }
            //删除token
            redisService.delete(RedisKeyStringUtils.appendRedisKey(RedisKeySystemConstants.REDIS_TOKEN, token));
        }
    }
}
